#include "CPetMgr.h"

#include <iostream>
#include <fstream>
#include <vector>
#include "pb_cfg_pet.pb.h"
#include "../mainctrl.h"
#include "commmsg.h"

int CPetMgr::Init()
{
    int iRet = 0;

    iRet = _stPetConfig.Init();
    CHECK_RETURN(iRet);

    m_aiExploreConfigEventRand.Clear();

    return 0;
}

int CPetMgr::LoadConfig(const char* szLogPath)
{/*{{{*/
    int iRet = 0;

    if (szLogPath == NULL)
    {
        CT_ERROR(("Pet Log Path is null"));
        return RET_SYSTEM_FAIL;
    }

    pb_cfg_pet  stPetPBConfig;
    std::fstream stFileInput(szLogPath, std::ios::in | std::ios::binary);
    if (!stPetPBConfig.ParseFromIstream(&stFileInput))
    {
        CT_ERROR(("Failed to Parse PetCfg!"));
        return RET_SYSTEM_FAIL;
    }

    //解析配置文件内容
    CT_TRACE(("pet config count %d", stPetPBConfig.pet_level_config_rows_size()));
    for (int i = 0; i < stPetPBConfig.pet_level_config_rows_size(); ++i)
    {
        const pb_cfg_pet_pb_cfg_pet_level_config_unit& stPetPBConfigUnit 
            = stPetPBConfig.pet_level_config_rows(i);

        CPetLevelConfigData stConfigData;
    
        //宠物等阶
        stConfigData._iPetLevel = stPetPBConfigUnit.pet_level();
        CT_TRACE(("宠物等阶ID %d", stConfigData._iPetLevel));

        //宠物等阶的所有属性
        CPetLevelAttr petLevelAttr;

        if( stPetPBConfigUnit.has_pet_attr_id1() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id1();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value1();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id2() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id2();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value2();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id3() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id3();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value3();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id4() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id4();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value4();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id5() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id5();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value5();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id6() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id6();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value6();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id7() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id7();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value7();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id8() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id8();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value8();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id9() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id9();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value9();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        if( stPetPBConfigUnit.has_pet_attr_id10() )
        {
            petLevelAttr.iAttrId = stPetPBConfigUnit.pet_attr_id10();
            petLevelAttr.iAttrValue = stPetPBConfigUnit.pet_attr_value10();
            stConfigData._aPetLevelAttrs.AddOneItem( petLevelAttr );
        }
        
        stConfigData._bHasConfig = true;
        iRet = this->_stPetConfig.AddPetLevelConfig( stConfigData ); 
        CHECK_RETURN(iRet);
    }

    //pet  explore cd time
    for (int i = 0; i < stPetPBConfig.explore_cd_time_rows_size(); ++i)
    {
        const pb_cfg_pet_pb_cfg_explore_cd_time_unit& stPetPBConfigUnit 
                 = stPetPBConfig.explore_cd_time_rows(i);

        CExploreCDTimeConfigData stConfigData;

        stConfigData._iExploreId    = stPetPBConfigUnit.explore_number_id(); //
        stConfigData._iDelayTimes   = stPetPBConfigUnit.cd_time(); //

        stConfigData._bHasConfig = true;
        iRet = this->_stPetConfig.AddExploreCDtimeConfig( stConfigData );
        CHECK_RETURN(iRet);
    }

    CT_TRACE(("pet star config count %d", stPetPBConfig.pet_star_config_rows_size()));
    for (int i = 0; i < stPetPBConfig.pet_star_config_rows_size(); ++i)
    {
        const pb_cfg_pet_pb_cfg_pet_star_config_unit& stPetPBConfigUnit 
                 = stPetPBConfig.pet_star_config_rows(i);

        CPetStarConfigData stConfigData;

        stConfigData._iPetLevel     = stPetPBConfigUnit.pet_level(); //
        stConfigData._iPetStar      = stPetPBConfigUnit.pet_star(); //
        stConfigData._iPhyAttack    = stPetPBConfigUnit.phyattack(); //
        stConfigData._iMagicAttack  = stPetPBConfigUnit.magicattack(); //
        stConfigData._iPhyDefend    = stPetPBConfigUnit.phydefend(); //
        stConfigData._iMagicDefend  = stPetPBConfigUnit.magicdefend(); //
        stConfigData._iNeedExp      = stPetPBConfigUnit.need_exp(); //
        stConfigData._iTrainSilver  = stPetPBConfigUnit.train_silver(); //
        stConfigData._iSilverExp    = stPetPBConfigUnit.silver_exp(); //
        stConfigData._iSilverCrit   = stPetPBConfigUnit.silver_crit_random(); //
        stConfigData._iTrainGold    = stPetPBConfigUnit.train_gold();
        stConfigData._iGoldExp      = stPetPBConfigUnit.gold_exp();
        stConfigData._iGoldCrit     = stPetPBConfigUnit.gold_crit_random();
        stConfigData._iGoldBigCrit  = stPetPBConfigUnit.gold_big_crit_random();

        stConfigData._bHasConfig = true;
        iRet = this->_stPetConfig.AddPetStarConfig( stConfigData );
        CHECK_RETURN(iRet);
    }

    CT_TRACE(("pet explore config count %d", stPetPBConfig.explore_config_rows_size()));
    for (int i = 0; i < stPetPBConfig.explore_config_rows_size(); ++i)
    {
        const pb_cfg_pet_pb_cfg_explore_config_unit& stPetPBConfigUnit
             = stPetPBConfig.explore_config_rows(i);

        CPetExploreConfigData   stConfigData;

        stConfigData._iExploreId = stPetPBConfigUnit.explore_id();

        if( stPetPBConfigUnit.award_item_type1() != 0 )
        {
            CPetExploreConfigData::TExploreAward tba;
            tba.iAwardItemType = stPetPBConfigUnit.award_item_type1();
            tba.iAwardItemId   = stPetPBConfigUnit.award_item_id1();
            tba.iAwardNum      = stPetPBConfigUnit.award_num1();

            stConfigData._aTExploreAwards.AddOneItem( tba );

            CT_TRACE(("探险奖励%d: 类型:%d,id:%d, 数量:%d", i, tba.iAwardItemType, tba.iAwardItemId, tba.iAwardNum));

            if( stPetPBConfigUnit.award_item_type2() != 0 )
            {
                tba.iAwardItemType = stPetPBConfigUnit.award_item_type2();
                tba.iAwardItemId   = stPetPBConfigUnit.award_item_id2();
                tba.iAwardNum      = stPetPBConfigUnit.award_num2();

                stConfigData._aTExploreAwards.AddOneItem( tba );

                CT_TRACE(("探险奖励%d: 类型:%d,id:%d, 数量:%d", i, tba.iAwardItemType, tba.iAwardItemId, tba.iAwardNum));

                if( stPetPBConfigUnit.award_item_type3() != 0 )
                {
                    tba.iAwardItemType = stPetPBConfigUnit.award_item_type3();
                    tba.iAwardItemId   = stPetPBConfigUnit.award_item_id3();
                    tba.iAwardNum      = stPetPBConfigUnit.award_num3();

                    stConfigData._aTExploreAwards.AddOneItem( tba );

                    CT_TRACE(("探险奖励%d: 类型:%d,id:%d, 数量:%d", i, tba.iAwardItemType, tba.iAwardItemId, tba.iAwardNum));

                    if( stPetPBConfigUnit.award_item_type4() != 0 )
                    {
                        tba.iAwardItemType = stPetPBConfigUnit.award_item_type4();
                        tba.iAwardItemId   = stPetPBConfigUnit.award_item_id4();
                        tba.iAwardNum      = stPetPBConfigUnit.award_num4();

                        stConfigData._aTExploreAwards.AddOneItem( tba );

                        CT_TRACE(("探险奖励%d: 类型:%d,id:%d, 数量:%d", i, tba.iAwardItemType, tba.iAwardItemId, tba.iAwardNum));
                    }
                }
            }
        }

        stConfigData._bHasConfig = true;
        iRet = this->_stPetConfig.AddPetExploreConfig( stConfigData );
        CHECK_RETURN(iRet);
        m_aiExploreConfigEventRand.AddOneItem( stConfigData._iExploreId );
    }

    return 0;
}/*}}}*/

int CPetMgr::PetClearCDTime(CUserPet& stUserPet)
{
    return stUserPet.PetClearCDTime();
}

//宠物探险
int CPetMgr::PetExplore(CUserPet& stUserPet, MsgAnsPetOther& stAns)
{
    int iRet = 0;

    CPetStarConfigData stStarData;
    iRet = this->GetPetStarConfig( stUserPet, stStarData );
    CHECK_RETURN(iRet);


    //检查是否达到可以探险的等级
    int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];
    if( !stUserPet.m_bCanExplore)
    {
        CT_ERROR(("%u current level %u not enough level for explore", stUserPet.GetUserGid(), stPlayerBaseInfo._shLevel));
        return ERROR_NOT_ENOUGH_LEVEL_TO_EXPLORE;
    }

    iIndex = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", stUserPet.GetUserGid()));
        return RET_SYSTEM_FAIL;

    }
    CPlayerOnlineData& stPlayerOnlineData = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash[iIndex];

    //检查有没有过cd时间
    int iCDTime = stUserPet.CheckCDTime();
    if( CMainCtrl::m_pstMain->m_iNow<=iCDTime )
    {
        return ERROR_NOT_COMPLETE_NEXT_EXPLORE_TIME;
    }

    //检查剩余探险次数
    int iExploreCounts = 0;
    iExploreCounts = stUserPet.GetPetExploreCounts();
    if( iExploreCounts<=0 )
    {
        return ERROR_NO_EXPLORE_COUNT;//探险次数用完
    }

    //从配置中取出探险奖励
    CPetExploreConfigData stData;
    //根据剩余次数取出乱序列表中的探险事件id
    int iExploreEventId = stUserPet.GetPetExploreId(iExploreCounts);
    iRet = this->_stPetConfig.GetPetExploreConfig(iExploreEventId, stData);
    CHECK_RETURN(iRet);

    //trigger explore award
    //iRet = TriggerExploreAward(stUserPet, stData);
    CDropItem stDropItem;
    iRet = TriggerExploreAwardWithLevel(stPlayerBaseInfo._shLevel, stUserPet, stData, stDropItem);
    CHECK_RETURN(iRet);

    //增加宠物经验
    stUserPet.TriggerIncrExper(stStarData._iSilverExp);
    CheckPetUpdate(stUserPet);
    stAns.set_get_exp(stStarData._iSilverExp);

    //返回探险奖励
    stAns.set_event_id( iExploreEventId );
    /*for( int i=0; i<stData._aTExploreAwards.Size(); ++i )
    {
        MsgGridItemInfo * awards = stAns.add_awards();
        awards->set_item_store_pos(0);
        awards->set_item_type(stData._aTExploreAwards[i].iAwardItemType);
        awards->set_item_config_id( stData._aTExploreAwards[i].iAwardItemId );
        awards->set_item_count( stData._aTExploreAwards[i].iAwardNum );
    }*/
    //显示给前台 返回奖励信息
    stDropItem.GetPBMsg(stUserPet.GetUserGid(), *(stAns.mutable_awards()));

    //取得冷却时间
    int iCDTimes = 0;
    int iSeqId = iExploreCounts-1;
    if( iSeqId<=0 )
    {
        iCDTimes = 0;
    }
    else
    {
        CExploreCDTimeConfigData stCDTimeData;
        iRet = this->_stPetConfig.GetExploreCDTimeConfig(MAX_PET_EXPLORE_DAILY_NUM-iSeqId, stCDTimeData);
        iCDTimes = stCDTimeData._iDelayTimes;
    }

    stUserPet.PetExplore(iCDTimes);

    //trigger daily task
    CMainCtrl::m_pstMain->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_2);

    return iRet;
}

int CPetMgr::GeneratePet(CUserPet& stUserPet, unsigned char _ucCareer)
{
    int iRet = 0;

    //是否要加一个标志来表示宠物已经生效，否则当前宠物还有生效，不能使用

    //是否要从这里去base里面取出当前用户的职业

    //初始化宠物属性
    iRet = stUserPet.Init( _ucCareer );

    return iRet;
}

int CPetMgr::TriggerExploreAwardWithLevel(short iLevel, CUserPet& stUserPet, CPetExploreConfigData& stConfigData, CDropItem& stDropItem)
{
    int iRet = 0;

    iRet = stUserPet.GetExploreAwardItemsWithLevel(iLevel, stConfigData, stDropItem);
    if (iRet != RET_OK)
    {
        CT_WARNING(("CPetMgr::TriggerPetExploreAward:get award items fail-%d", iRet));
        return ERROR_EXPLORE_AWARD_ITEM;
    }

    //assign award items to user
    stDropItem.SetOssModule(OSS_MODULE_PET);
    iRet = CMainCtrl::m_pstMain->m_stItemMgr.DropItem(NULL, stUserPet.GetUserGid(), stDropItem);

    return iRet;
}

int CPetMgr::TriggerExploreAward(CUserPet& stUserPet, CPetExploreConfigData& stConfigData)
{
    int iRet = 0;
    CDropItem stDropItem;

    iRet = stUserPet.GetExploreAwardItems(stConfigData, stDropItem);
    if (iRet != RET_OK)
    {
        CT_WARNING(("CPetMgr::TriggerPetExploreAward:get award items fail-%d", iRet));
        return ERROR_EXPLORE_AWARD_ITEM;
    }

    //assign award items to user
    stDropItem.SetOssModule(OSS_MODULE_PET);
    iRet = CMainCtrl::m_pstMain->m_stItemMgr.DropItem(NULL, stUserPet.GetUserGid(), stDropItem);

    return iRet;
}

int CPetMgr::GetPetStarConfig(CUserPet& stUserPet, CPetStarConfigData & stData)
{
    int iRet = 0;

    iRet = _stPetConfig.GetPetStarConfig(stUserPet.GetPetLevel(), stUserPet.GetPetStar(), stData);
    CHECK_RETURN(iRet);
    
    return iRet;
}

int CPetMgr::GetPetStarConfig(int iLevel, int iStar, CPetStarConfigData & stData)
{
    int iRet = 0;

    iRet = _stPetConfig.GetPetStarConfig(iLevel, iStar, stData);

    CHECK_RETURN(iRet);
    
    return iRet;
}

bool CPetMgr::ConsumeRand(int uiMax, int uiRateVal)
{
    unsigned int iRate = CT_RANDOM_NUM->GetRand((unsigned int)uiMax); 

    if( iRate <= (unsigned int)uiRateVal )
    {
        return true;
    }

    return false;
}

//批量口粮培养
int CPetMgr::PetTrainKouLiangBatch(CUserPet& stUserPet, int iTrainNums, MsgAnsPetTrain&  stAns)
{
    int iRet = 0;
    int iCurLevel = 0;
    int iCurStar = 0;
    int iCurExper = 0;
    CPetStarConfigData stData;
    int iCritNums = 0;      //小暴击的次数
    int iBigCritNums = 0;   //大暴击的次数
    int iIncrExper = 0;     //批量培养总共获得经验值
    CTLib::CTArray<int, MAX_PET_AWARD_FRUIT_NUM> aAwardFruits;

    if(stUserPet.GetPetLevel() >= MAX_PET_LEVEL_CONFIG && stUserPet.GetPetStar() >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];

    bool iKouLiangTrainOneTime = false;
    if( iTrainNums==1 )
    {
        iKouLiangTrainOneTime = true;
    }
    //首先需要检查皇家口粮的数量和金币是否够消耗不够的口粮部分 ---start
    iIndex = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", stUserPet.GetUserGid()));
        return ERROR_NO_SUCH_USER;
    }
    CPlayerOnlineData& stPlayerOnlineData = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash[iIndex];

    iIndex = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash.HashFind(stUserPet.GetUserGid());
    CPlayerDetailInfo& stPlayerDetailInfo = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash[iIndex];

    //查询皇家口粮数量
    int iKouLiangNumInStore = 0; //首先使用皇家口粮
    iKouLiangNumInStore = CMainCtrl::m_pstMain->m_stStorageMgr.GetItemCount( stPlayerOnlineData._stUserStorage, HKOULIANGTYPE, HKOULIANGID );
    //计算培养要消耗的皇家口粮个数和金币培养的次数

    //20130910策划要求把符石培养恢复而注释
    /*if (iTrainNums > iKouLiangNumInStore)
    {
        return ERROR_PET_TRAIN_NOT_ENOUGH_KOULIANG;
    }*/
    
    int iGoldNumTrain = iTrainNums - iKouLiangNumInStore;      //剩余不够的部分使用金币培养
    int iConsumeGoldNum = iGoldNumTrain * TRAIN_GOLD_NUM;      //计算需要消耗多少金币

    //在cmdact里面已经做了用户数据存在的检查，这里直接用
    if( iConsumeGoldNum > stPlayerBaseInfo._iGold )
    {
        CT_WARNING(("gid = %u, not enough gold to batch train", stUserPet.GetUserGid()));
        return ERROR_PET_TRAIN_NOT_ENOUGH_GOLD;
    }
    //首先需要检查皇家口粮的数量和金币是否够消耗不够的口粮部分 ---end

    iCurLevel = stUserPet.GetPetLevel();
    iCurStar = stUserPet.GetPetStar();
    iCurExper = stUserPet.GetPetExper();

    //1.检查是否为每天的前三次金币培养
    int iDailyCritNum = stUserPet.GetPetCritCountsNotUpdate();

    int iCircleTimes = 0;   //记录循环执行次数
    for( int i=0; i<iTrainNums; ++i )
    {
        this->_stPetConfig.GetPetStarConfig(iCurLevel, iCurStar, stData);
        //stData._iNeedExp, 星级升级需要经验
        //stData._iTrainGold,培养需要金币
            
        bool bTrainFinish = false;
        int iAddExperOne = 0;
        if( iDailyCritNum > 0 )
        {
            //必须为暴击
            iAddExperOne = CONST_PET_CRIT_EXPER * stData._iGoldExp;

            iCritNums += 1;

            iDailyCritNum--;

            bTrainFinish = true;
        }

        //2.考虑大暴击
        if( !bTrainFinish )
        {
            bool bRate = false;
            bRate = this->ConsumeRand( MAX_RATE_VALUE * 10, stData._iGoldBigCrit );
            if( bRate )
            {
                //alter 2013.05.17大暴击直接升星级,但不再保留当前经验
                //iAddExperOne = stData._iNeedExp;
                iAddExperOne = iCurExper>=stData._iNeedExp ? 0:(stData._iNeedExp-iCurExper);

                iBigCritNums += 1;

                bTrainFinish = true;
            }
        }

        //3.考虑暴击
        if( !bTrainFinish )
        {
            bool bRate = false;
            bRate = this->ConsumeRand( MAX_RATE_VALUE, stData._iGoldCrit);
            if( bRate )
            {
                iAddExperOne = CONST_PET_CRIT_EXPER * stData._iGoldExp;

                iCritNums += 1;

                bTrainFinish = true;
            }
        }

        //4.到此只有普通金币培养
        if( !bTrainFinish )
        {
            iAddExperOne = stData._iGoldExp;

            bTrainFinish = true;
        }

        iCurExper += iAddExperOne;
        iIncrExper += iAddExperOne;

        if( iKouLiangTrainOneTime ) //单次的口粮培养，不能自动升阶
        {
            DesignLevelStarUpdateOneTime( iCurLevel, iCurStar, iCurExper, aAwardFruits );
        }
        else
        {
            DesignLevelStarUpdate( iCurLevel, iCurStar, iCurExper, aAwardFruits );
        }

        //检查是否达到最大等阶
        if( iCurLevel>=MAX_PET_LEVEL_CONFIG && iCurStar>=MAX_PET_STAR-1 )
        {
            break;
        }

        iCircleTimes++;
    }

    //消耗皇家口粮和金币
    int iGoldConsumeTimes = iCircleTimes>=iKouLiangNumInStore ? iCircleTimes-iKouLiangNumInStore:0;
    int iKouLiangConsumeTimes = iCircleTimes>=iKouLiangNumInStore ? iKouLiangNumInStore:iCircleTimes;
    if( iKouLiangConsumeTimes>0 ) //根据实际培养的次数来消耗口粮
    {
        iRet = CMainCtrl::m_pstMain->m_stStorageMgr.TakeOutItem(stPlayerOnlineData._stUserStorage, HKOULIANGTYPE, HKOULIANGID, iKouLiangConsumeTimes);
        CHECK_RETURN(iRet);
    }
    iConsumeGoldNum = iGoldConsumeTimes * TRAIN_GOLD_NUM;      //计算真实需要消耗多少金币
    if( iConsumeGoldNum>0 )
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_20, iConsumeGoldNum);            
        CHECK_RETURN(iRet);
    }

    //将每天的前三次金币培养数消耗完
    for( int i=0; i<iCritNums && stUserPet.GetPetCritCountsNotUpdate()>0; ++i )
    {
        stUserPet.TriggerCritNumDesc();
    }

    //将新生成的中间宠物信息更新到用户宠物数据中去
    stUserPet.SetPetInfoBatch(iCurLevel, iCurStar, iCurExper, aAwardFruits); 

    //推送背包仓库中的皇家口粮消耗信息 //发送大小暴击,获得多少经验值返回信息
    stAns.set_crit_small( iCritNums ); //小暴击次数
    stAns.set_crit_big( iBigCritNums );   //大暴击次数
    stAns.set_exper_incr( iIncrExper ); //本次培养增加经验值
    stAns.set_consume_huangkoul_num( iKouLiangConsumeTimes );  // //消耗皇家口粮数量
    stAns.set_consume_gold_num( iConsumeGoldNum );   //消耗金币数量
    stAns.set_gid( stUserPet.GetUserGid() );   

    //入库背包仓库
    CMainCtrl::m_pstMain->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stUserPet.GetUserGid();
    CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    //刷新背包/仓库数据 //推送金币剩余信息
    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stUserPet.GetUserGid(), NOTIFY_USER_MONEY | NOTIFY_BAG_INFO | NOTIFY_WARE_INFO);
    
    //推送宠物基本信息
    stUserPet.UpdatePetStatus();

    //对于单次培养，大暴击和升级要做全服广播
    if( iTrainNums==1 )
    {
        if( iBigCritNums>0 )//大暴击全服广播
        {
            PetBroadcast(stUserPet, 2);
        }
        //升阶需要用户主动发起，这里不做广播
        /*if( iUpdateLevel==1 )//升阶全服广播
        {
            PetBroadcast(stUserPet, 1);
        }*/
    }

    return iRet;
}

//检查满级 && 检查是否有果实未领取
int CPetMgr::CheckPetTrain( CUserPet& stUserPet )
{
    int iRet = 0;
    //检查是否达到最大等阶
    int iCurLevel = stUserPet.GetPetLevel();
    int iCurStar = stUserPet.GetPetStar();
    if( iCurStar>=MAX_PET_STAR || (iCurLevel>=MAX_PET_LEVEL_CONFIG && iCurStar>=MAX_PET_STAR-1) )
    {
        return ERROR_PET_LEVEL_MAX;
    }

    //检查是否有果实未领取
    if( stUserPet.HasFruitNotRecv() )
    {
        return ERROR_HAS_FRUIT_NOT_RECV;
    }

    return iRet;
}

//单次皇家口粮的培养，不能自动升阶
int CPetMgr::DesignLevelStarUpdateOneTime( int & iLevel, int & iStar, int & iCurExper, FruitAwardArray & aAwardFruits )
{
    int iRet = 0;
    CPetStarConfigData stData;
    int iPetFruit = 0;
    int iPetNextFruit = 0;

    if(iLevel >= MAX_PET_LEVEL_CONFIG && iStar >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    //aAwardFruits.Clear();

    iRet = this->GetPetStarConfig( iLevel, iStar, stData );
    CHECK_RETURN(iRet);

    while( iCurExper>0 && iCurExper>=stData._iNeedExp )//星级升级
    {
        iStar += 1;
        iCurExper = iCurExper - stData._iNeedExp;

        /*不能自动升阶
        if( iStar>=MAX_PET_STAR )
        {
            iLevel += 1;
            iStar -= MAX_PET_STAR;
        }*/

        //检查是否达到最大等阶
        if( iLevel>=MAX_PET_LEVEL_CONFIG && iStar>=MAX_PET_STAR-1 )
        {
            iLevel = MAX_PET_LEVEL_CONFIG;
            iStar = MAX_PET_STAR-1;
            iCurExper = 0;
        }

        //检查是否发放果实，13579星级可以奖励果实，当前星级和下一果实星级的两个果实
        if( iStar==1 || iStar==3 || iStar==5 || iStar==7 || iStar==9 )
        {
            //放置奖励果实给前台
            iPetFruit = MAX_PET_LEVEL_CONFIG * iLevel + iStar;
            aAwardFruits.AddOneItem( iPetFruit );

            //检查是否达到最大等阶
            if( !(iLevel>=MAX_PET_LEVEL_CONFIG && iStar>=MAX_PET_STAR-1) )
            {
                iPetNextFruit = iPetFruit + 2;  //没达到最大星级要给鱼下一星级奖励果实

                if( iPetNextFruit<MAX_PET_LEVEL_CONFIG * MAX_PET_LEVEL_CONFIG + MAX_PET_STAR )
                {
                    aAwardFruits.AddOneItem( iPetNextFruit );
                }
            }
        }

        //检查是否达到最大等阶
        if( iLevel>=MAX_PET_LEVEL_CONFIG && iStar>=MAX_PET_STAR-1 )
        {
            break;
        }

        this->GetPetStarConfig( iLevel, iStar, stData );
    }

    return iRet;
}

//批量培养的升级计算
int CPetMgr::DesignLevelStarUpdate( int & iLevel, int & iStar, int & iCurExper, FruitAwardArray & aAwardFruits )
{
    int iRet = 0;
    CPetStarConfigData stData;
    int iPetFruit = 0;
    int iPetNextFruit = 0;

    if(iLevel >= MAX_PET_LEVEL_CONFIG && iStar >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    //aAwardFruits.Clear();

    iRet = this->GetPetStarConfig( iLevel, iStar, stData );
    CHECK_RETURN(iRet);

    while( iCurExper>0 && iCurExper>=stData._iNeedExp )//星级升级
    {
        iStar += 1;
        iCurExper = iCurExper - stData._iNeedExp;

        //检查升阶
        if( iStar>=MAX_PET_STAR )
        {
            iLevel += 1;
            iStar -= MAX_PET_STAR;
        }

        //检查是否达到最大等阶
        if( iLevel>=MAX_PET_LEVEL_CONFIG && iStar>=MAX_PET_STAR-1 )
        {
            iLevel = MAX_PET_LEVEL_CONFIG;
            iStar = MAX_PET_STAR-1;
            iCurExper = 0;
        }

        //检查是否发放果实，13579星级可以奖励果实，当前星级和下一果实星级的两个果实
        if( iStar==1 || iStar==3 || iStar==5 || iStar==7 || iStar==9 )
        {
            //放置奖励果实给前台
            iPetFruit = MAX_PET_LEVEL_CONFIG * iLevel + iStar;
            aAwardFruits.AddOneItem( iPetFruit );

            //检查是否达到最大等阶
            if( !(iLevel>=MAX_PET_LEVEL_CONFIG && iStar>=MAX_PET_STAR-1) )
            {
                iPetNextFruit = iPetFruit + 2;  //没达到最大星级要给鱼下一星级奖励果实

                if( iPetNextFruit<MAX_PET_LEVEL_CONFIG * MAX_PET_LEVEL_CONFIG + MAX_PET_STAR )
                {
                    aAwardFruits.AddOneItem( iPetNextFruit );
                }
            }
        }

        //检查是否达到最大等阶
        if( iLevel>=MAX_PET_LEVEL_CONFIG && iStar>=MAX_PET_STAR-1 )
        {
            break;
        }

        this->GetPetStarConfig( iLevel, iStar, stData );
    }

    return iRet;
}

//宠物口粮培养
int CPetMgr::PetTrainKouLiang(CUserPet& stUserPet, int iKouLiangNum, int iGridPos, MsgAnsPetTrain& stAns)
{
    int iRet = 0;

    if(stUserPet.GetPetLevel() >= MAX_PET_LEVEL_CONFIG && stUserPet.GetPetStar() >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    CPetStarConfigData stData;
    if( iKouLiangNum==CONST_PET_FRUIT_BAT_NUM ) //批量口粮培养,vip>=3专用
    {
        int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
        CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];

        //vip>3
        if( stPlayerBaseInfo._chVipLevel<3 )
        {
            CT_ERROR(("gid = %u, vip level too low,can't batch train",stUserPet.GetUserGid()));
            return ERROR_VIP_LEVEL_NOT_ENOUGH;
        }

        iRet = this->PetTrainKouLiangBatch(stUserPet, iKouLiangNum, stAns);
        CHECK_RETURN(iRet);
    }
    else
    {
        //单个皇家口粮培养
        iRet = this->PetTrainKouLiangBatch(stUserPet, 1, stAns);
        CHECK_RETURN(iRet);
    }

    return iRet;
}


//金币培养
int CPetMgr::PetTrainGold(CUserPet& stUserPet, int iGoldNum)
{
    int iRet = 0;
    int iGetBigCrit = 0;

    if(stUserPet.GetPetLevel() >= MAX_PET_LEVEL_CONFIG && stUserPet.GetPetStar() >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    CPetStarConfigData stData;

    iRet = this->GetPetStarConfig( stUserPet, stData );
    CHECK_RETURN(iRet);

    int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("base user %u not in hash", stUserPet.GetUserGid()));
        return -1;
    }
    CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];

    //判断消耗金币数量
    /*if( iGoldNum!=stData._iTrainGold )
    {
        iRet = ERROR_PET_TRAIN_GOLD_NUM;

        CT_WARNING(("CPetMgr::PetTrainGold fail-%d", iRet));

        return iRet;
    }*/
    iGoldNum = stData._iTrainGold;

    //判断用户是否有足够的金币
    if( stPlayerBaseInfo._iGold < iGoldNum )
    {
        iRet = ERROR_PET_TRAIN_NOT_ENOUGH_GOLD;

        CT_WARNING(("CPetMgr::PetTrainGold fail-%d", iRet));

        return iRet;
    }

    bool bTrainFinish = false;
    //1.检查是否为每天的前三次金币培养
    int iDailyCritNum = stUserPet.GetPetCritCountsNotUpdate();
    if( iDailyCritNum > 0 )
    {
        //必须为暴击
        stUserPet.TriggerIncrExper(CONST_PET_CRIT_EXPER * stData._iGoldExp);

        //每天的前三次金币培养数递减
        stUserPet.TriggerCritNumDesc();

        bTrainFinish = true;
    }

    //2.考虑大暴击
    if( !bTrainFinish )
    {
        bool bRate = false;
        bRate = this->ConsumeRand( MAX_RATE_VALUE * 10, stData._iGoldBigCrit );
        if( bRate )
        {
            stUserPet.TriggerBigCrit();

            iGetBigCrit = 1;

            bTrainFinish = true;
        }
    }

    //2.考虑暴击
    if( !bTrainFinish )
    {
        bool bRate = false;
        bRate = this->ConsumeRand( MAX_RATE_VALUE, stData._iGoldCrit);
        if( bRate )
        {
            stUserPet.TriggerIncrExper(CONST_PET_CRIT_EXPER * stData._iGoldExp);

            bTrainFinish = true;
        }
    }

    //4.到此只有普通金币培养
    if( !bTrainFinish )
    {
        stUserPet.TriggerIncrExper(stData._iGoldExp);

        bTrainFinish = true;
    }

    //消耗金币
    if( bTrainFinish )
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_29, stData._iTrainGold);                    
    }
    
    //检查星级和等阶的升级
    //int iUpdateLevel = CheckPetUpdate( stUserPet, stData );
    int iUpdateLevel = CheckPetUpdate( stUserPet );

    if( iGetBigCrit==1 )//大暴击全服广播
    {
        PetBroadcast(stUserPet, 2);
    }

    if( iUpdateLevel==1 )//升阶全服广播
    {
        PetBroadcast(stUserPet, 1);
    }    

    return iRet;
}

//检查星级和等阶的升级
//int CPetMgr::CheckPetUpdate(CUserPet& stUserPet, CPetStarConfigData& stData)
int CPetMgr::CheckPetUpdate(CUserPet& stUserPet)
{
    int iRet = 0;

    iRet = stUserPet.CheckPetUpdate();

    return iRet;
}

//银币培养
int CPetMgr::PetTrainSilver(CUserPet& stUserPet, int iSilverNum, MsgAnsPetTrain&  stAns)
{
    int iRet = 0;

    if(stUserPet.GetPetLevel() >= MAX_PET_LEVEL_CONFIG && stUserPet.GetPetStar() >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    CPetStarConfigData stData;
    int iCritNums = 0;      //小暴击的次数
    int iBigCritNums = 0;   //大暴击的次数
    int iIncrExper = 0;     //培养总共获得经验值

    iRet = this->GetPetStarConfig( stUserPet, stData );
    CHECK_RETURN(iRet);

    int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("base user %u not in hash", stUserPet.GetUserGid()));
        return -1;
    }
    CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];

    //判断消耗银币数量
    /*if( iSilverNum!=stData._iTrainSilver )
    {
        iRet = ERROR_PET_TRAIN_SILVER_NUM;

        CT_WARNING(("CPetMgr::PetTrainSilver fail-%d", iRet));

        return iRet;
    }*/
    iSilverNum = stData._iTrainSilver;

    //判断用户是否有足够的银币
    if( stPlayerBaseInfo._i64Silver < iSilverNum )
    {
        iRet = ERROR_PET_TRAIN_NOT_ENOUGH_SILVER;

        CT_WARNING(("CPetMgr::PetTrainSilver fail-%d", iRet));

        return iRet;
    }

    bool bTrainFinish = false;
    //1.考虑暴击
    if( !bTrainFinish )
    {
        bool bRate = false;
        bRate = this->ConsumeRand( MAX_RATE_VALUE, stData._iSilverCrit);
        if( bRate )
        {
            int iIncrExperThis = CONST_PET_CRIT_EXPER * stData._iSilverExp;
            stUserPet.TriggerIncrExper(iIncrExperThis);

            iCritNums += 1;
            iIncrExper += iIncrExperThis;
            bTrainFinish = true;
        }
    }

    //4.到此只有普通银币培养
    if( !bTrainFinish )
    {
        stUserPet.TriggerIncrExper(stData._iSilverExp);

        iIncrExper += stData._iSilverExp;
        bTrainFinish = true;
    }

    //消耗银币
    if( bTrainFinish )
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubSilver(stPlayerBaseInfo, stData._iTrainSilver, 0);
    }

    //推送背包仓库中的皇家口粮消耗信息 //发送大小暴击,获得多少经验值返回信息
    stAns.set_crit_small( iCritNums ); //小暴击次数
    stAns.set_crit_big( iBigCritNums );   //大暴击次数
    stAns.set_exper_incr( iIncrExper ); //本次培养增加经验值
    stAns.set_consume_huangkoul_num( 0 );  // 消耗皇家口粮数量
    stAns.set_consume_gold_num( 0 );   //消耗金币数量
    stAns.set_gid( stUserPet.GetUserGid() );   

    //刷新背包/仓库数据 //推送金币剩余信息
    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stUserPet.GetUserGid(), NOTIFY_USER_MONEY);

    //检查星级和等阶的升级
    //int iCURet = CheckPetUpdate( stUserPet );
    CheckPetUpdate( stUserPet );
    /*if( iCURet==1 )
    {
        PetBroadcast(stUserPet, 1);
    }*/

    return iRet;
}

//广播类型,type=1, 宠物等阶升级， type=2,宠物获得大暴击
int CPetMgr::PetBroadcast(CUserPet& stUserPet, int type)
{
    int iRet = 0;
    //Broadcast
    CTArray<unsigned int, MAX_PLAYER_ONLINE> astGIDArray;

    PBMsgHead stMsgHead;
    stMsgHead.set_time(CMainCtrl::m_pstMain->m_iNow);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    stMsgHead.set_msgid(ID_MAIN_TIPS);
    stMsgHead.set_msgret(RET_OK);

    MsgTips stAns;
    char szCritContent[] = "大暴击";
    char szUpLevelContent[] = "宠物升阶";
    char szResult[512] = {0};

    int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("base user %u not in hash", stUserPet.GetUserGid()));
        return -1;
    }
    CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];
 
    if( !(type==1 || type==2) )
    {
        CT_WARNING(("Error broadcast message type"));
        return -1;
    }

    stAns.set_type(0); //基础广播

    switch( type )
    {
    case 1:
        sprintf( szResult, "%s 宠物获得 %s", stPlayerBaseInfo._sRoleName(), szUpLevelContent );
        break;
    case 2:
        sprintf( szResult, "%s 宠物获得 %s", stPlayerBaseInfo._sRoleName(), szCritContent);
        break;
    }
    stAns.set_msg( szResult );

    CMainCtrl::m_pstMain->m_stPlayerOnline.GetAllOnlineUser(astGIDArray);
    for (int i = 0; i < astGIDArray.Size(); ++i)
    {
        CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();

        CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
        CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);
        CMainCtrl::m_pstMain->NotifyOnlineUser(astGIDArray[i], CMainCtrl::m_pstMain->m_stEncodeBuf);
    }

    return iRet;
}

//果实培养
int CPetMgr::PetTrainFruit(CUserPet& stUserPet, int iFruitNum, int iGridPos)
{
    int iRet = 0;

    if (stUserPet.GetPetHasEatFruit() >= MAX_PET_CAN_EAT_FRUIT)
    {
        return ERROR_PET_FRUIT_FULL;
    }

    //int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    //CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];

    int iIndex = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", stUserPet.GetUserGid()));
        return ERROR_NO_SUCH_USER;
    }
    CPlayerOnlineData& stPlayerOnlineData = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash[iIndex];

    iIndex = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash.HashFind(stUserPet.GetUserGid());
    CPlayerDetailInfo& stPlayerDetailInfo = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash[iIndex];

    //果实信息需要利用iGridPos位置从背包查询得到 //查询背包中是否有果实
    CStorageGrid stGrid; 
    iRet = CMainCtrl::m_pstMain->m_stStorageMgr.GetGridInfoByPos(stPlayerOnlineData._stUserStorage, true, iGridPos, stGrid);

    //验证果实类型
    if( stGrid._stKey._ucItemType!=PET_FRUIT_TYPE )
    {
        CT_ERROR(("gid = %u, fruit train in bag type=%d, is not a fruit", stUserPet.GetUserGid(), stGrid._stKey._ucItemType));
        return ERROR_TRAIN_FRUIT_IS_NOT_FRUIT;
    }
    //查询果实配置
    CFruitUnitConfig stConfigData;
    iRet = CMainCtrl::m_pstMain->m_stItemMgr.GetFruitConfig( stGrid._stKey._uiItemID, stConfigData );
    CHECK_RETURN(iRet);

    //检查当前星级够不够吃此果实
    int iFruitLevel = stConfigData._ucLevel;
    int iFruitStar  = stConfigData._ucStar;
    if( !( (stUserPet.GetPetLevel()>iFruitLevel) || 
           (stUserPet.GetPetLevel()==iFruitLevel && stUserPet.GetPetStar()>= iFruitStar) 
         ) )
    {
        CT_ERROR(("gid = %u, pet current level:star(%d|%d) fruit level:star(%d|%d) can't eat ", stUserPet.GetUserGid(), stUserPet.GetPetLevel(), 
                                        stUserPet.GetPetStar(), iFruitLevel, iFruitStar));
        return ERROR_CURRENT_LEVELSTAR_CAN_FRUIT_TRAIN;
    }

    //检查果实有没有过期
    if( CMainCtrl::m_pstMain->m_iNow>=stGrid._iInvalidTime )
    {
        CT_ERROR(("gid = %u, pet current level:star(%d|%d) fruit level:star(%d|%d) can't eat, is timeoff ", stUserPet.GetUserGid(), stUserPet.GetPetLevel(), 
                                        stUserPet.GetPetStar(), iFruitLevel, iFruitStar));
        return ERROR_FRUIT_IS_FAILURE_TIME;
    }
    
    //消耗果实
    iRet = CMainCtrl::m_pstMain->m_stStorageMgr.TakeOutItem(stPlayerOnlineData._stUserStorage, iGridPos, 1);
    CHECK_RETURN(iRet);
    
    //星级能力增益1%
    if( iRet == RET_OK )
    {
        stUserPet.PetTrainFruit();
    }
    else
    {
        CT_WARNING(("CPetMgr::TriggerPetExploreAward:get award items fail-%d", iRet));
    }
    
    //入库背包仓库
    CMainCtrl::m_pstMain->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stUserPet.GetUserGid();
    CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    //刷新背包/仓库数据 //推送金币剩余信息
    iRet = CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stUserPet.GetUserGid(), NOTIFY_BAG_INFO);

    return iRet;
}

//改变宠物形态
int CPetMgr::PetChangeStyle(CUserPet& stUserPet, int iPetNewStyle)
{
    int iRet = 0;

    //if( iPetNewStyle>=1 && iPetNewStyle<=4 )
    //修改为现在只有两种形态，猫头鹰和猫
    if( iPetNewStyle==PET_STATUS_TYPE_OWL || iPetNewStyle==PET_STATUS_TYPE_CAT )
    {
        iRet = stUserPet.PetChangeStyle(iPetNewStyle);
    }
    else
    {
        iRet = ERROR_PET_STYLE;
    }

    return iRet;
}

int CPetMgr::PetEnableNewStyle(CUserPet& stUserPet, int iPetNewStyle)
{
    //目前只能激活猫的形态
    if (iPetNewStyle!=PET_STATUS_TYPE_CAT)
    {
        return ERROR_PET_STYLE;
    }
    
    return stUserPet.PetEnableNewStyle(iPetNewStyle);
}

//领取果实
int CPetMgr::PetRecvFruit(CUserPet& stUserPet)
{
    int iRet = 0;

    iRet = stUserPet.PetRecvFruit();

    return iRet;
}

//宠物请求升等阶
int CPetMgr::PetReqUpdateLevel(CUserPet& stUserPet)
{
    int iRet = 0;

    iRet = stUserPet.PetReqUpdateLevel();
    if( iRet==RET_OK )
    {
        PetBroadcast(stUserPet, 1); //升等阶
    }

    return iRet;
}

//取得宠物id，战斗中用到
int CPetMgr::GetPetId(CUserPet& stUserPet, int &iPetId)
{
    int iRet = 0;

    /*CPetData stUserPetData;
    iRet = stUserPet.GetData(stUserPetData);
    if (iRet != RET_OK)
    {
        CT_WARNING(("get pet info error:%u", stUserPet.GetUserGid()));
        return iRet;
    }*/
    CPetData& stUserPetData = stUserPet.GetDataRef();

    iPetId = stUserPetData._iPetStyle * 100 + stUserPetData._iPetLevel;

    return iRet;
}

int CPetMgr::GetPetInfo(CUserPet& stUserPet, MsgAnsPetInfo& stPetInfoAns)
{
    int iRet = 0;


    /*
    //目前测试阶段，直接设置宠物激活----------start--------------
    int iIndex = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash.HashFind(stUserPet.GetUserGid());
    if (iIndex < 0)
    {
        CT_ERROR(("base user %u not in hash", stUserPet.GetUserGid()));
        return -1;
    }
    CPlayerBaseInfo& stPlayerBaseInfo = CMainCtrl::m_pstMain->m_stPlayerBaseInfoHash[iIndex];
    //iRet = this->GeneratePet(stUserPet, stPlayerBaseInfo._ucCareer);
    //CHECK_RETURN( iRet );
    //目前测试阶段，直接设置宠物激活----------end--------------
    */

    iRet = stUserPet.PetIsActive();
    if( iRet==0 )
    {
        CT_WARNING(("user %u not have pet", stUserPet.GetUserGid()));
        stPetInfoAns.set_ret(ERROR_NOT_HAVE_PET); 
        return 0;
    }

    /*CPetData stUserPetData;
    iRet = stUserPet.GetData(stUserPetData);
    if (iRet != RET_OK)
    {
        CT_WARNING(("get pet info error:%u", stUserPet.GetUserGid()));
        return iRet;
    }*/
    CPetData& stUserPetData = stUserPet.GetDataRef();

    stPetInfoAns.set_gid( stUserPet.GetUserGid() );
    stPetInfoAns.set_pet_type( stUserPetData._iPetStyle );
    stPetInfoAns.set_level( stUserPetData._iPetLevel);
    stPetInfoAns.set_star( stUserPetData._iPetStar);
    stPetInfoAns.set_cur_star_exper( stUserPetData._iPetExper);
    //stPetInfoAns.set_explore_count( stUserPetData._iExploreCountInDay);
    if( stUserPet.m_bCanExplore )
    {
    stPetInfoAns.set_explore_count( stUserPetData._sExploreCountInDay.Get( CMainCtrl::m_pstMain->m_iNow ) );
    }
    stPetInfoAns.set_star_gain( stUserPetData._iPetFruit);
    stPetInfoAns.set_nickname( stUserPetData._sPetName.Get() );
    stPetInfoAns.set_explore_cd_time( stUserPetData._iNextCDTime );
    stPetInfoAns.set_is_recv_fruit( stUserPetData._iIsRecvFruit );
    
    if( stUserPetData._iIsRecvFruit==CONST_PET_HAS_FRUIT_NOT_RECV )
    {
        for( int i=0; i<stUserPetData._aPetAwardFruits.Size(); ++i )
        {
            MsgGridItemInfo * awards = stPetInfoAns.add_awards();
            awards->set_item_store_pos(0);
            awards->set_item_type(PET_FRUIT_TYPE);
            awards->set_item_config_id( stUserPetData._aPetAwardFruits[i] );
            awards->set_item_count(1);
        }
        //stPetInfoAns.set_awards( 果实奖励，2个);
    }

    stPetInfoAns.set_max_style_id(stUserPetData._iPetMaxCanUseStyle);

    return iRet;
}

//取得宠物属性信息
int CPetMgr::GetPetAttrInfo(CUserPet & stUserPet, MsgPet& stMsgPetInfo)
{

    CPetData& stUserPetData = stUserPet.GetDataRef();

    stMsgPetInfo.set_level(stUserPetData._iPetLevel);
    stMsgPetInfo.set_star(stUserPetData._iPetStar);
	stMsgPetInfo.set_active(stUserPetData._iIsActive);
    stMsgPetInfo.set_pet_type( stUserPetData._iPetStyle );
    stMsgPetInfo.set_star_gain( stUserPetData._iPetFruit);
    stMsgPetInfo.set_max_style_id(stUserPetData._iPetMaxCanUseStyle);
	return 0;
}

//获取宠物战斗力
int CPetMgr::GetPetLevelStarFruit(CUserPet& stUserPet, int & iLevel, int& iStar, int& iFruitNum)
{
    return stUserPet.GetPetLevelStarFruit(iLevel, iStar, iFruitNum);
}

//获取宠物能力信息
int CPetMgr::GetPetAttr(CUserPet& stUserPet, CPlayerAttr& astPetAttrs)
{
    int iRet = 0;

    astPetAttrs.Clear();

    //星级属性
    CPetStarConfigData stStarConfigData;
    iRet = this->GetPetStarConfig( stUserPet, stStarConfigData );
    CHECK_RETURN(iRet);

    //等阶属性
    CPetLevelConfigData stLevelConfigData;
    iRet = this->_stPetConfig.GetPetLevelConfig( stUserPet.GetPetLevel(), stLevelConfigData );
    CHECK_RETURN(iRet);

    iRet = stUserPet.GetPetAttrs(stLevelConfigData, stStarConfigData, astPetAttrs);

    return iRet;
}

int CPetMgr::GMPetTrain(CUserPet& stUserPet, int iTrainExper)
{
    int iRet = 0;

    if(stUserPet.GetPetLevel() >= MAX_PET_LEVEL_CONFIG && stUserPet.GetPetStar() >= MAX_PET_STAR-1)
    {
        return ERROR_PET_LEVEL_MAX;
    }

    int iCurLevel = 0;
    int iCurStar = 0;
    int iCurExper = 0;
    CTLib::CTArray<int, 50> aAwardFruits;

    iCurLevel = stUserPet.GetPetLevel();
    iCurStar = stUserPet.GetPetStar();
    iCurExper = stUserPet.GetPetExper();

    iCurExper += iTrainExper;

    iRet = this->DesignLevelStarUpdate( iCurLevel, iCurStar, iCurExper, aAwardFruits );

    //将新生成的中间宠物信息更新到用户宠物数据中去
    stUserPet.SetPetInfoBatch(iCurLevel, iCurStar, iCurExper, aAwardFruits); 

    //推送宠物基本信息
    stUserPet.UpdatePetStatus();

    return iRet;
}

ExploreRandArray& CPetMgr::GetExploreRandArray()
{
    return this->m_aiExploreConfigEventRand;
}

int CPetMgr::CheckNewPetName(CTSizeString<PETNAME_LEN>& szPetName)
{
    int iRet = 0;
    CMainCtrl* pstMainCtrl = CMainCtrl::m_pstMain;

    //检查字符集编码方式
    const char * sNowCharSet = pstMainCtrl->m_stCharSetConvertMgr.GetCharset(szPetName(), szPetName.GetDataLen(), iRet);
    if (sNowCharSet == NULL || iRet != 0)
    {
        CT_WARNING(("ret = %d, char set %s", iRet, (sNowCharSet == NULL ? "NULL" : sNowCharSet)));
        return ERROR_WRONG_NAME_CHAR_SET;
    }

    if (strncmp("UTF-8", sNowCharSet, sizeof("UTF-8")) != 0
        && strlen(sNowCharSet) != 0)
    {
        CT_WARNING(("char set %s, name = %s", (sNowCharSet == NULL ? "NULL" : sNowCharSet), szPetName()));
        return ERROR_WRONG_NAME_CHAR_SET;
    }

    //检查长度
    int iNameLen = pstMainCtrl->m_stSenWordMgr.GetStringWidth(szPetName());
    if (iNameLen < MIN_ROLENAME_LEN || iNameLen > MAX_ROLENAME_LEN)
    {
        return ERROR_WRONG_NAME;
    }

    //检查单字节屏蔽字
    for (int i = 0; i < szPetName.GetDataLen(); ++i)
    {
        unsigned char ucChar = szPetName()[i];
        if (ucChar < 128)
        {
            if ((ucChar >= '0' && ucChar <= '9')
                || (ucChar >= 'a' && ucChar <= 'z')
                || (ucChar >= 'A' && ucChar <= 'Z'))
            {
                continue;
            }
            else
            {
                return ERROR_HAS_SEN_WORD;
            }
        }
    }

    /*
    iRet = pstMainCtrl->m_stSenWordMgr.queryNickName( szRoleName() );
    if (iRet > 0)
    {
        CT_TRACE(("role name = %s, ret %d, sen word %s", szRoleName(), iRet, iRet==2?"special char":"sensitive word"));
        return ERROR_HAS_SEN_WORD;
    }*/

    return 0;
}

int CPetMgr::GetPetExploreConfigCounts()
{
    return this->_stPetConfig.GetPetExploreConfigCounts();
}
